﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using OpcDa.Client;

namespace OpcTestClient
{
    public partial class MainForm : Form
    {
        private OpcServer _opcServer;
        private IRequest _request = null;
        private int _handle = 0;

        public MainForm()
        {
            InitializeComponent();

            // update interface state
            this.txtGroupName.Enabled = false;
            this.txtUpdateRate.Enabled = false;
            this.txtItemName1.Enabled = false;
            this.txtItemName2.Enabled = false;
            this.txtItemName3.Enabled = false;
            this.txtItemName4.Enabled = false;
            this.btnAddGroup.Enabled = false;
            this.btnAddItems.Enabled = false;
            this.btnRemoveItems.Enabled = false;
            this.listView1.Enabled = false;

            this.btnAysnRead.Enabled = false;
            this.btnAsyncWrite.Enabled = false;
            this.btnRefresh.Enabled = false;

            //this.txtProgID.Text = "OPCSample.OpcDa20Server.1";
            this.txtGroupName.Text = "Grp_0";
            this.txtUpdateRate.Text = "1000";
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (this.btnConnect.Text == "Connect")
            {
                if (string.IsNullOrEmpty(this.txtProgID.Text))
                {
                    MessageBox.Show("ProgId can not be empty.");
                    return;
                }

                if (this._opcServer != null)
                {
                    this._opcServer.Disconnect();
                    this._opcServer = null;
                }

                Type tp = Type.GetTypeFromProgID(this.txtProgID.Text);
                this._opcServer = new OpcServer(tp.GUID.ToString(), this.txtHostName.Text);
                
                try
                {
                    this._opcServer.Connect();
                
                    // connected to Opc server
                    this.btnConnect.Text = "Disconnect";
                    this.lbStatus.Text = "Server is running normally.";

                    // update interface state
                    this.txtProgID.Enabled = false;
                    this.txtHostName.Enabled = false;
                    this.txtGroupName.Enabled = true;
                    this.txtUpdateRate.Enabled = true;
                    this.btnAddGroup.Enabled = true;
                  
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, 
                        "Error", 
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Error);
                }
            }
            else // disconnect
            {
                if (this._opcServer != null)
                {
                    this._opcServer.Disconnect();
                    this._opcServer = null;
                }

                this.btnConnect.Text = "Connect";
                this.lbStatus.Text = "Click \'Connect\' button to connect a Server";

                // update interface state
                this.txtProgID.Enabled = true;
                this.txtHostName.Enabled = true;

                this.txtGroupName.Enabled = false;
                this.txtUpdateRate.Enabled = false;
                this.btnAddGroup.Enabled = false;
         
            }
        }

        private void btnAddGroup_Click(object sender, EventArgs e)
        {
            if (this.btnAddGroup.Text == "Add")
            {
                if (this._opcServer == null)
                    return;

                try
                {
                    OpcGroup grp = this._opcServer.AddGroup(this.txtGroupName.Text, int.Parse(this.txtUpdateRate.Text), true);
                    if (grp != null)
                    {
                        grp.DataChanged += OnDataChange;
                        this.btnAddGroup.Text = "Remove";

                        // update interface state
                        this.txtGroupName.Enabled = false;
                        this.txtUpdateRate.Enabled = false;
                        this.txtItemName1.Enabled = true;
                        this.txtItemName2.Enabled = true;
                        this.txtItemName3.Enabled = true;
                        this.txtItemName4.Enabled = true;
                        this.btnAddGroup.Enabled = true;
                        this.btnAddItems.Enabled = true;
                        this.btnRemoveItems.Enabled = true;
                        this.listView1.Enabled = true;

                        this.btnAysnRead.Enabled = true;
                        this.btnAsyncWrite.Enabled = true;
                        this.btnRefresh.Enabled = true;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message,
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                }
            }
            else //remove
            {

                // check if any items exist, remove items first
                this.RemoveOpcItems(this.listView1.Items);

                OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
                if (grp != null)
                {
                    try
                    {
                        grp.DataChanged -= OnDataChange;
                        this._opcServer.RemoveGroup(grp);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message,
                                            "Error",
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error);

                    } // end catch
                }
                this.btnAddGroup.Text = "Add";

                this.txtGroupName.Enabled = true;
                this.txtUpdateRate.Enabled = true;
                this.txtItemName1.Enabled = false;
                this.txtItemName2.Enabled = false;
                this.txtItemName3.Enabled = false;
                this.txtItemName4.Enabled = false;
                this.btnAddGroup.Enabled = true;
                this.btnAddItems.Enabled = false;
                this.btnRemoveItems.Enabled = false;
                this.listView1.Enabled = false;

                this.btnAysnRead.Enabled = false;
                this.btnAsyncWrite.Enabled = false;
                this.btnRefresh.Enabled = false;
            }
        }

        private void OnDataChange(object subscriptionHandle, object requestHandle, ItemValueResult[] values)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new DataChangedEventHandler(OnDataChange), new object[] { subscriptionHandle, requestHandle, values });
                return;
            }

          
            foreach (ItemValueResult value in values)
            {
                // item value should never have a null client handle.
                if (value.ClientHandle == null)
                {
                    continue;
                }
                UpdateListViewItem(value);
            }
        }

        /// <summary>
		/// Called when an asynchronous read request completes.
		/// </summary>
        private void OnReadComplete(object clientHandle, ItemValueResult[] values)
        {
            try
            {
                if (InvokeRequired)
                {
                    BeginInvoke(new ReadCompleteEventHandler(OnReadComplete), new object[] { clientHandle, values });
                    return;
                }

                if (!_handle.Equals(clientHandle))
                {
                    return;
                }

                foreach (ItemValueResult value in values)
                {
                    // item value should never have a null client handle.
                    if (value.ClientHandle == null)
                    {
                        continue;
                    }

                    if (value.ResultID.Failed())
                    {
                        string message = "Failed to read item \'" + value.ItemName + "\' error: " + value.ResultID.ToString();
                        MessageBox.Show(message);
                    }
                    else
                    {
                        UpdateListViewItem(value);
                    }
                }
            }
            catch
            {
            }
        }

        private void OnWriteComplete(object clientHandle, IdentifiedResult[] results)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new WriteCompleteEventHandler(OnWriteComplete), new object[] { clientHandle, results });
                return;
            }

            if (!_handle.Equals(clientHandle))
            {
                return;
            }

            foreach (IdentifiedResult result in results)
            {
                // item value should never have a null client handle.
                if (result.ClientHandle == null)
                {
                    continue;
                }

                if (result.ResultID.Failed())
                {
                    string message = "Failed to write item \'" + result.ItemName + "\' error: " + result.ResultID.ToString();
                    MessageBox.Show(message);
                }
            }
        }

        private void UpdateListViewItem(ItemValueResult value)
        {
            ListViewItem item = this.GetListViewItem(value.ClientHandle);
            if (item != null)
            {
                if (value.Value != null)
                {
                    item.SubItems[1].Text = value.Value.ToString();
                    item.SubItems[1].Tag = value.Value;
                }
                item.SubItems[2].Text = value.Quality.ToString();
                item.SubItems[3].Text = (int.Parse(item.SubItems[3].Text) + 1).ToString();
            }
        }


        private void btnAddItems_Click(object sender, EventArgs e)
        {

            List<string> items = new List<string>();
            if (!string.IsNullOrEmpty(this.txtItemName1.Text))
            {
                items.Add(this.txtItemName1.Text);
                this.txtItemName1.Text = string.Empty;
            }

            if (!string.IsNullOrEmpty(this.txtItemName2.Text))
            {
                items.Add(this.txtItemName2.Text);
                this.txtItemName2.Text = string.Empty;
            }

            if (!string.IsNullOrEmpty(this.txtItemName3.Text))
            {
                items.Add(this.txtItemName3.Text);
                this.txtItemName3.Text = string.Empty;
            }

            if (!string.IsNullOrEmpty(this.txtItemName4.Text))
            {
                items.Add(this.txtItemName4.Text);
                this.txtItemName4.Text = string.Empty;
            }

            if (items.Count <= 0)
            {
                MessageBox.Show("No item(s) to be added.");
                return;
            }

            OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
            if (grp != null)
            {
                try
                {
                    ItemResult[] results = grp.AddItems(items.ToArray());
                    foreach (ItemResult result in results)
                    {
                        if (result.ResultID.Failed())
                        {
                            string message = "Failed to add item \'" + result.ItemName + "\'" + " Error: " + result.ResultID.Name;
                            MessageBox.Show(message);
                        }
                        else
                        {
                            AddItemToList(result);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message,
                                        "Error",
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);

                } // end catch
            }
        }

        private void AddItemToList(ItemResult result)
        {
            ListViewItem lvItem = new ListViewItem();
            lvItem.Text = result.ItemName;
            lvItem.StateImageIndex = lvItem.ImageIndex = 0;
            lvItem.SubItems.Add("No Value");
            lvItem.SubItems.Add("No Quality");
            lvItem.SubItems.Add("0");
            lvItem.Tag = result;

            this.listView1.Items.Add(lvItem);
        }

        private void RemoveItemFromList(IdentifiedResult result)
        {
            lock (this.listView1)
            {
                this.listView1.BeginUpdate();

                ListViewItem item = this.GetListViewItem(result.ClientHandle);
                if (item != null)
                    this.listView1.Items.Remove(item);

                this.listView1.EndUpdate();
            }
        }

        private ListViewItem GetListViewItem(object itemClientHandle)
        {
            foreach (ListViewItem item in this.listView1.Items)
            {
                ItemResult result = (ItemResult)item.Tag;
                if (result != null &&
                    Guid.Equals(result.ClientHandle, itemClientHandle))
                {
                    return item;
                }
            }
            return null;
        }

        private void btnRemoveItems_Click(object sender, EventArgs e)
        {
           ListView.SelectedListViewItemCollection items = this.listView1.SelectedItems;
           if (items.Count > 0)
           {
               this.RemoveOpcItems(items);
           }
           else
           {
                   MessageBox.Show("Please select item(s) you want to remove.");
                   return;
           }
        }

        private void RemoveOpcItems(IList items)
        {
            if (items.Count > 0)
            {
                // get selected items client handle
                List<object> itemsClientHandle = new List<object>();
                foreach (ListViewItem lvItem in items)
                {
                    ItemResult result = (ItemResult)lvItem.Tag;
                    if (result != null)
                    {
                        itemsClientHandle.Add(result.ClientHandle);
                    }
                }

                // remove items
                if (itemsClientHandle.Count > 0)
                {
                    try
                    {
                        // get group
                        OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
                        if (grp != null)
                        {
                            IdentifiedResult[] results = grp.RemoveItems(itemsClientHandle.ToArray());
                            for (int i = 0; i < results.Length; i++)
                            {
                                if (results[i].ResultID.Succeeded())
                                {
                                    // remove opc item from server successfully, remove it from list
                                    RemoveItemFromList(results[i]);
                                }
                                else
                                {
                                    string message = "Remove item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString();
                                    MessageBox.Show(message);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message,
                                            "Error",
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error);

                    } // end catch
                }
            }
        }

        private void btnAysnRead_Click(object sender, EventArgs e)
        {
            ListView.SelectedListViewItemCollection items = this.listView1.SelectedItems;
            if (items.Count <= 0)
            {
                MessageBox.Show("Please select the items to read.");
                return;
            }
            List<object> clientHandles = new List<object>();
            foreach (ListViewItem lvItem in items)
            {
                ItemResult item = (ItemResult)lvItem.Tag;
                if (item != null)
                {
                    clientHandles.Add(item.ClientHandle);
                }
            }
            if (clientHandles.Count > 0)
            {
                // get group
                OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
                if (grp != null)
                {
                    try
                    {
                        IdentifiedResult[] results = grp.AsyncRead(clientHandles.ToArray(), ++this._handle, new ReadCompleteEventHandler(OnReadComplete), out this._request);
                        for (int i = 0; i < results.Length; i++)
                        {
                            if (results[i].ResultID.Failed())
                            {
                                string message = "Failed to read item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString();
                                MessageBox.Show(message);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }

        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this._opcServer != null)
            {
                this._opcServer.Disconnect();
                this._opcServer = null;
            }
        }

        private void btnAsyncWrite_Click(object sender, EventArgs e)
        {
            ListView.SelectedListViewItemCollection items = this.listView1.SelectedItems;
            if (items.Count <= 0)
            {
                MessageBox.Show("Please select the item to Write.");
                return;
            }

            foreach (ListViewItem lvItem in items)
            {
                ItemResult item = (ItemResult)lvItem.Tag;
                if (item != null)
                {
                    ItemValue itemValue = new ItemValue(item);

                    object value = lvItem.SubItems[1].Tag;
                    itemValue.Value = value;

                    WriteItemValueDlg dlg = new WriteItemValueDlg(itemValue);
                    if (DialogResult.OK == dlg.ShowDialog())
                    {
                        // get group
                        OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
                        if (grp != null)
                        {
                            try
                            {
                                IdentifiedResult[] results = grp.AsyncWrite(new ItemValue[] {dlg._itemValue}, ++_handle, new WriteCompleteEventHandler(this.OnWriteComplete), out _request);
                                for (int i = 0; i < results.Length; i++)
                                {
                                    if (results[i].ResultID.Failed())
                                    {
                                        string message = "Failed to write item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString();
                                        MessageBox.Show(message);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.Message);
                            }
                        }
                    }
                }
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            // get group
            OpcGroup grp = this._opcServer.FindGroupByName(this.txtGroupName.Text);
            if (grp != null)
            {
                grp.Refresh();
            }
        }

     


      
    }
}

